package agriculture.controller;

import agriculture.bean.Payment;
import agriculture.config.AlipayTemplate;
import agriculture.config.RabbitMQConfig;
import agriculture.dto.OrderPaidMessage;
import agriculture.service.PaymentService;
import agriculture.util.RedisLockUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import lombok.RequiredArgsConstructor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequiredArgsConstructor
public class PaymentController {
    private final AlipayTemplate alipayTemplate;

    private final PaymentService paymentService;

    private final RabbitTemplate rabbitTemplate;

    private final RedisLockUtil redisLockUtil;

    /**
     * 创建支付宝支付请求
     * @param payment 支付请求参数（包括订单号、支付金额、支付方式）
     * @param response 用于写出 HTML 表单
     */
    @PostMapping("/payment/alipay")
    public void createAlipayPayment(@RequestBody Payment payment, HttpServletResponse response) {

        System.out.println("支付系统----------------------");

        String lockKey = "payment:lock:" + payment.getOrderNumber();
        String lockValue = RedisLockUtil.generateLockValue();

        boolean locked = redisLockUtil.tryLock(lockKey, lockValue, 30); // 锁 30 秒
        if (!locked) {
            throw new RuntimeException("系统繁忙，请稍后重试（重复下单防护）");
        }
        try {
            //幂等校验，查新数据库中是否已有该订单，且支付
           Payment existing = paymentService.lambdaQuery()
                    .eq(Payment::getOrderNumber,payment.getOrderNumber()).one();

               if (existing != null && "PAID".equals(existing.getPayStatus())){
                   throw new RuntimeException("该订单已支付，请勿重复提交");
               }

            // 调用服务层创建支付请求
            String form = paymentService.createAlipayPayment(payment);

            // 设置响应类型为 HTML
            response.setContentType("text/html;charset=" + "utf-8");

            // 写出表单字符串，页面将自动跳转到支付宝支付页面
            response.getWriter().write(form);
            response.getWriter().flush();
        } catch (AlipayApiException | IOException e) {
            e.printStackTrace();
            throw new RuntimeException("支付发起失败: " + e.getMessage());
        }finally {
           boolean unlocked = redisLockUtil.unlock(lockKey, lockValue); // 释放锁
            if (!unlocked){
                System.out.println("解锁失败：锁已过期或不是当前线程加的锁！");
            }
        }
    }

    /**
     * 支付回调，此方法是支付宝支付成功后，
     * 后台异步通知接口（即服务器之间的通信，不经过前端）。必须部署公网地址或内网穿透才能收到。
     * @param request
     * @return
     */
    @PostMapping("/api/payment/alipay/notif")
    public String alipayNotify(HttpServletRequest request) {
        System.out.println("回调层-------------------");
        Map<String, String> params = new HashMap<>();
        request.getParameterMap().forEach((key, values) -> params.put(key, values[0]));

        boolean signVerified;
        //使用支付宝提供的工具类验证签名是否合法，确保回调信息未被篡改
        try {
            signVerified = AlipaySignature.rsaCheckV1(
                    params,
                    alipayTemplate.getAlipayPublicKey(),
                    alipayTemplate.getCharset(),
                    alipayTemplate.getSignType()
            );
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return "fail";
        }

        if (signVerified) {
            String outTradeNo = params.get("out_trade_no");//订单号
            String tradeNo = params.get("trade_no"); //支付宝交易号
            String gmtPayment = params.get("gmt_payment"); //支付时间

            // 更新数据库支付状态为 PAID
            Payment payment = paymentService.lambdaQuery()
                    .eq(Payment::getOrderNumber, outTradeNo)
                    .one();

            if (payment != null && !"PAID".equals(payment.getPayStatus())) {
                //幂等处理，只处理未支付的订单
                payment.setPayStatus("PAID");
                payment.setNotifyTime(LocalDateTime.parse(gmtPayment, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                payment.setTradeNo(tradeNo);
                paymentService.updateById(payment);
            }
            // ✅ 发送 MQ 消息通知订单服务
            OrderPaidMessage message = new OrderPaidMessage();
            message.setOrderNumber(outTradeNo);
            message.setTradeNo(tradeNo);
            message.setPayTime(payment.getNotifyTime());
            message.setPaymentMethod(payment.getPayType());
            message.setQuantity(payment.getQuantity());

            /**
             * rabbitTemplate: 是 Spring Boot 提供的操作 RabbitMQ 的模板工具类。
             * convertAndSend()：表示发送消息并自动将 Java 对象转换成 JSON，底层使用消息转换器。
             * RabbitMQConfig.EXCHANGE_NAME：交换机名称（定义在配置类中）。
             * RabbitMQConfig.ROUTING_KEY：消息路由 key（决定发给哪个队列）。
             * message：我们刚刚构造的消息对象。
             */
            rabbitTemplate.convertAndSend(
                    RabbitMQConfig.EXCHANGE_NAME,
                    RabbitMQConfig.ROUTING_KEY,
                    message
            );

            System.out.println("发送mq消息通知订单服务");
            return "success";
        } else {
            return "fail";
        }
    }

}

